package com.eight.cloud.auth.common.security;

import com.eight.cloud.auth.common.config.AuthConfig;
import com.eight.cloud.auth.common.filter.AuthLoginFilter;
import com.eight.cloud.auth.common.security.provider.TenantUsernamePasswordAuthenticationProvider;
import com.eight.cloud.auth.common.security.provider.VerificationCodeAuthenticationProvider;
import com.eight.cloud.openfeign.admin.api.UserClient;
import com.eight.cloud.redisson.utils.TokenManager;
import com.eight.cloud.security.config.AuthAccessDeniedHandler;
import com.eight.cloud.security.config.BaseUrlAuthorizationManager;
import com.eight.cloud.security.config.PermitProperties;
import com.eight.cloud.security.config.UnAuthEntryPoint;
import com.eight.cloud.security.filter.AuthorityFilter;
import com.eight.cloud.security.filter.JwtRequestFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: SecurityConfig
 * @Author: TXC
 * @Date: 2024-10-25 10:13
 **/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {
    @Resource
    private UnAuthEntryPoint unAuthEntryPoint;
    @Resource
    private UserDetailsService userDetailService;
    @Resource
    private AuthAccessDeniedHandler accessDeniedHandler;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private AuthorityFilter authorityFilter;
    @Resource
    private JwtRequestFilter jwtRequestFilter;
    @Resource
    private AuthLogoutHandler authLogoutHandler;
    @Resource
    private TokenManager tokenManager;
    @Resource
    private PermitProperties permitProperties;
    @Resource
    private BaseUrlAuthorizationManager baseUrlAuthorizationManager;
    @Resource
    private UserClient userClient;
    @Resource
    private AuthConfig authConfig;


    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        http.csrf(AbstractHttpConfigurer::disable)
                // 允许跨域访问
                .cors(e -> e.configure(http))
                .formLogin().disable()
                .authenticationManager(authenticationManager())
                // 不需要session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .logout(logout -> logout.logoutUrl("/logout").addLogoutHandler(authLogoutHandler))
                // 没有权限访问时默认的返回值
                .exceptionHandling(exception -> exception.accessDeniedHandler(accessDeniedHandler).authenticationEntryPoint(unAuthEntryPoint))
                .authorizeHttpRequests(httpRequest ->
                        httpRequest
                                // 放行接口
                                .regexMatchers(HttpMethod.OPTIONS, "/*").permitAll()
                                .antMatchers(permitProperties.getIgnore()).permitAll()
                                .anyRequest().access(baseUrlAuthorizationManager))
                // 登录拦截器
                .addFilter(new AuthLoginFilter(tokenManager, authenticationManager(), authConfig))
                // 权限拦截器
                .addFilterBefore(authorityFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }

    /**
     * 获得用户名和密码的登陆方式
     */
    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailService);
        provider.setPasswordEncoder(passwordEncoder);
        return provider;
    }

    /**
     * 验证码登陆方式
     */
    @Bean
    public VerificationCodeAuthenticationProvider verificationCodeAuthenticationProvider() {
        return new VerificationCodeAuthenticationProvider();
    }

    /**
     * 验证码登陆方式
     */
    @Bean
    public TenantUsernamePasswordAuthenticationProvider tenantUsernamePasswordAuthenticationProvider() {
        TenantUsernamePasswordAuthenticationProvider provider = new TenantUsernamePasswordAuthenticationProvider();
        provider.setUserClient(userClient);
        return provider;
    }


    /**
     * 定义身份管理器 并注入身份提供者
     */
    @Bean
    protected AuthenticationManager authenticationManager() {
        List<AuthenticationProvider> providerList = new ArrayList<>();
        providerList.add(daoAuthenticationProvider());
        providerList.add(verificationCodeAuthenticationProvider());
        providerList.add(tenantUsernamePasswordAuthenticationProvider());
        return new ProviderManager(providerList);
    }
}
